#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# xhs_search_dropdown.py

"""
单一博主主页爬虫
使用Playwright自动获取单一博主主页信息
"""

import os
import sys
import re
import random
from datetime import datetime, timedelta

# 添加项目根目录到Python路径
current_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(current_dir))

# 初始化playwright配置
from playwright.sync_api import sync_playwright
from config import AUTH_FILE, Config

# 相关变量初始化
html_url = "https://www.xiaohongshu.com/explore/67cbf6a8000000002a00fe84?xsec_token=ABCUg7YdTOpKAeiJ842gPpmUwjEHMTV4ZdEzCkd8kgH4E=&xsec_source=pc_feed"

def process_like_count(like_text):
    """处理点赞数，如果出错则返回原值"""
    try:
        return '0' if like_text == '赞' else like_text
    except Exception as e:
        print(f"处理点赞数出错: {e}, 原始值: {like_text}")
        return like_text

def process_time(time_text):
    """处理时间格式，如果出错则返回原值"""
    try:
        now = datetime.now()
        
        # 处理"刚刚"
        if time_text == "刚刚":
            return now.strftime("%Y-%m-%d")
        
        # 处理"今天 HH:MM"
        if time_text.startswith("今天"):
            return now.strftime("%Y-%m-%d")
        
        # 处理"昨天 HH:MM"
        if time_text.startswith("昨天"):
            yesterday = now - timedelta(days=1)
            return yesterday.strftime("%Y-%m-%d")
        
        # 处理"N 天前"
        if "天前" in time_text:
            days = int(time_text.split()[0])
            past_date = now - timedelta(days=days)
            return past_date.strftime("%Y-%m-%d")
        
        # 处理"MM-DD"格式
        if len(time_text) == 5 and "-" in time_text:
            return f"{now.year}-{time_text}"
        
        return time_text
    except Exception as e:
        print(f"处理时间出错: {e}, 原始值: {time_text}")
        return time_text

def main(html_url):
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=Config.IF_HEADLESS)
        context = browser.new_context(storage_state=AUTH_FILE if os.path.exists(AUTH_FILE) else None)  
        page = context.new_page()

        # 跳转至落地页
        page.goto(html_url, wait_until="commit")

        # 等待评论容器加载
        page.wait_for_selector("div.comments-container")
        
        # 展示显示更多的回复

        # 处理问题1：展开所有"显示更多"回复
        def expand_all_replies():
            while True:
                # 查找所有"显示更多"按钮
                show_more_buttons = page.query_selector_all("div.reply-container > div.show-more")
                if not show_more_buttons:
                    break
                
                for button in show_more_buttons:
                    try:
                        # 确保按钮可见
                        if button.is_visible():
                            # 点击按钮
                            button.click()
                            # 等待新评论加载
                            page.wait_for_timeout(random.choice([1000, 2000]))  # 等待1秒让内容加载
                    except Exception as e:
                        print(f"点击显示更多按钮时出错: {e}")
                
                # 短暂等待以防止过快点击
                page.wait_for_timeout(500)

        # 评论区父评论懒加载
        def scroll_and_load_comments():
            # 先点击内部元素激活评论窗口
            page.locator('div.total').click()

            # 记录初始parent-comment长度, 循环次数
            initial_parent_comment_len = len(page.locator('div.comments-container div.parent-comment').all())
            consecutive_same_count = 0  # 连续相同次数计数
            i = 0

            # 循环懒加载
            while True:
                # 模拟滚轮
                page.mouse.wheel(0, random.randint(800, 1500))

                # 随机等待时间
                page.wait_for_timeout(random.randint(1500, 2500))

                middle_parent_comment_len = len(page.locator('div.comments-container div.parent-comment').all())
                print(f"第{i}次循环：初始长度为:{initial_parent_comment_len}, 结束长度为:{middle_parent_comment_len}")

                # 检查评论数是否变化
                if middle_parent_comment_len == initial_parent_comment_len:
                    consecutive_same_count += 1
                    if consecutive_same_count >= 5:  # 连续5次没有变化则退出
                        print("连续5次未加载新评论，退出循环")
                        return
                else:
                    consecutive_same_count = 0  # 如果有新评论加载，重置计数器

                initial_parent_comment_len = middle_parent_comment_len
                i += 1

        def extract_comment_info(page):
            # 获取所有评论信息
            comments_data = page.evaluate("""
                () => {
                    const comments = [];
                    // 获取所有父评论
                    document.querySelectorAll('div.parent-comment').forEach(parentDiv => {
                        // 获取父评论信息
                        const parentComment = parentDiv.querySelector('div.comment-item');
                        const parentAuthorLink = parentComment.querySelector('.author .name');
                        const parentData = {
                            comment_id: parentComment.id.replace('comment-', ''),
                            author: parentAuthorLink.innerText,
                            user_id: parentAuthorLink.getAttribute('data-user-id') || '',
                            content: parentComment.querySelector('.note-text').innerText,
                            likes: parentComment.querySelector('.like .count').innerText,
                            time: parentComment.querySelector('.date span').innerText,
                            location: parentComment.querySelector('.location')?.innerText || '',
                            replies: []
                        };
                        
                        // 获取子评论信息
                        const replyContainer = parentDiv.querySelector('.reply-container');
                        if (replyContainer) {
                            replyContainer.querySelectorAll('.comment-item-sub').forEach(replyDiv => {
                                const replyAuthorLink = replyDiv.querySelector('.author .name');
                                const replyData = {
                                    comment_id: replyDiv.id.replace('comment-', ''),
                                    author: replyAuthorLink.innerText,
                                    user_id: replyAuthorLink.getAttribute('data-user-id') || '',
                                    content: replyDiv.querySelector('.note-text').innerText,
                                    likes: replyDiv.querySelector('.like .count').innerText,
                                    time: replyDiv.querySelector('.date span').innerText,
                                    location: replyDiv.querySelector('.location')?.innerText || '',
                                    reply_to: replyDiv.querySelector('.nickname')?.innerText || ''
                                };
                                parentData.replies.push(replyData);
                            });
                        }
                        
                        comments.push(parentData);
                    });
                    return comments;
                }
            """)
            
            # 处理评论数据
            try:
                for comment in comments_data:
                    try:
                        # 处理父评论
                        comment['likes'] = process_like_count(comment['likes'])
                        comment['time'] = process_time(comment['time'])
                    except Exception as e:
                        print(f"处理父评论数据出错: {e}")
                    
                    # 处理回复
                    try:
                        for reply in comment['replies']:
                            reply['likes'] = process_like_count(reply['likes'])
                            reply['time'] = process_time(reply['time'])
                    except Exception as e:
                        print(f"处理回复数据出错: {e}")
            except Exception as e:
                print(f"处理评论数据出错: {e}")
            
            return comments_data

        try:
            # 1. 首先处理懒加载，加载所有评论
            scroll_and_load_comments()
            
            # 2. 展开所有回复
            expand_all_replies()
            
            # 处理完懒加载和展开回复后，提取评论信息
            comments_data = extract_comment_info(page)
            
            # 打印评论信息（用于调试）
            for comment in comments_data:
                print(f"\n父评论 ID: {comment['comment_id']}")
                print(f"作者: {comment['author']}")
                print(f"用户ID: {comment['user_id']}")
                print(f"内容: {comment['content']}")
                print(f"点赞: {comment['likes']}")
                print(f"时间: {comment['time']}")
                print(f"地点: {comment['location']}")
                
                if comment['replies']:
                    print("\n回复:")
                    for reply in comment['replies']:
                        print(f"  |- 评论 ID: {reply['comment_id']}")
                        print(f"  |- 作者: {reply['author']}")
                        print(f"  |- 用户ID: {reply['user_id']}")
                        print(f"  |- 回复给: {reply['reply_to']}")
                        print(f"  |- 内容: {reply['content']}")
                        print(f"  |- 点赞: {reply['likes']}")
                        print(f"  |- 时间: {reply['time']}")
                        print(f"  |- 地点: {reply['location']}")
                        print("  |")
            
            # 可以选择将数据保存到文件
            import json
            with open('comments.json', 'w', encoding='utf-8') as f:
                json.dump(comments_data, f, ensure_ascii=False, indent=2)
            
        except Exception as e:
            print(f"爬取过程中出错: {e}")
            import traceback
            print(traceback.format_exc())
        finally:
            # 保存登录状态
            context.storage_state(path=AUTH_FILE)
            browser.close()

        

if __name__ == "__main__":
    main('https://www.xiaohongshu.com/explore/67ce8426000000002602c4ce?xsec_token=ABm7p3LIDT5AM1HRigVMGr1lv-BOeFKixXO3lotrbgNk4=&xsec_source=pc_feed')

